﻿using MongoRepository;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using Tradukisto.Model;
using Tradukisto.Model.Special;


namespace Tradukisto.DataAccess
{
    public class Manager
    {
        private static string connectionString = "";

         static Manager()
        {
            connectionString = ConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString;
            if (string.IsNullOrEmpty(connectionString))
            {
                var temp = ConfigurationManager.ConnectionStrings["MONGOLAB_URI"];
                if (temp != null)
                {
                    connectionString = temp.ConnectionString;
                }
            }
            if (string.IsNullOrEmpty(connectionString))
            {
                connectionString = ConfigurationManager.AppSettings["MONGOLAB_URI"];
            }
        }

        #region LocalItem CRUD operations
        public static List<LocalItem> FilterLocalItems(FilterItems filterValues)
        {

            var repo = new MongoRepository<LocalItem>(connectionString);
            var ret = repo.All();

            if (!string.IsNullOrEmpty(filterValues.ControllerName))
            {
                ret = ret.Where(p => p.ControllerName.Equals(filterValues.ControllerName.ToLower()));
            }

            if (!string.IsNullOrEmpty(filterValues.Culture))
            {
                ret = ret.Where(p => p.Culture.Equals(filterValues.Culture));
            }

            if (!string.IsNullOrEmpty(filterValues.ActionName))
            {
                ret = ret.Where(p => p.ActionName.Equals(filterValues.ActionName.ToLower()));
            }

            if (!string.IsNullOrEmpty(filterValues.Name))
            {
                ret = ret.Where(p => p.Name.Contains(filterValues.Name.ToLower()));
            }

            if (!string.IsNullOrEmpty(filterValues.Value))
            {
                ret = ret.Where(p => p.Value.Contains(filterValues.Value));
            }

            if (!string.IsNullOrEmpty(filterValues.Id))
            {
                ret = ret.Where(p => p.Id == filterValues.Id);
            }

            return ret.ToList();
        }

        public static SaveResults SaveLocalItem(LocalItem itemToSave)
        {
            var ret = SaveResults.GeneralError;

            try
            {
                var repo = new MongoRepository<LocalItem>(connectionString);

                if (repo.All().Count(p => p.Name == itemToSave.Name && p.Id != itemToSave.Id && p.Culture == itemToSave.Culture) > 0)
                {
                    return SaveResults.Duplicate;
                }

                bool isNew = false;
                if (string.IsNullOrEmpty(itemToSave.Id))
                {
                    itemToSave.Id = Guid.NewGuid().ToString();
                    isNew = true;
                }

                itemToSave.ActionName = itemToSave.ActionName.ToLower().Trim();
                itemToSave.ControllerName = itemToSave.ControllerName.ToLower().Trim();
                itemToSave.Name = itemToSave.Name.ToLower().Trim();

                var taskController = Task.Factory.StartNew(() => { HandleControllers(itemToSave.ControllerName); });
                var taskCulture = Task.Factory.StartNew(() => { HandleCultures(itemToSave.Culture); });
                Task.WaitAll(taskController, taskCulture);

                var taskAction = Task.Factory.StartNew(() => { HandleActions(itemToSave.ActionName, itemToSave.ControllerName); });
                if (isNew)
                {
                    var taskOtherCultures = Task.Factory.StartNew(() => { SaveOtherCultures(itemToSave); });
                }
                repo.Update(itemToSave);

                ret = SaveResults.OK;

                return ret;
            }
            catch (Exception e)
            {
                ret = SaveResults.GeneralError;
                throw;
            }
        }

        public static bool DeleteLocalItem(string id)
        {
            try
            {
                var repo = new MongoRepository<LocalItem>(connectionString);
                var ret = repo.All().SingleOrDefault(p => p.Id == id);
                if (ret != null)
                {
                    repo.Delete(ret);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
        }

        private static void SaveOtherCultures(LocalItem itemTosave)
        {
            var repoCultures = new MongoRepository<Culture>(connectionString);
            var cultures = repoCultures.All().Where(p => p.Name != itemTosave.Culture).Select(p => p.Name).ToList();

            var repoLocal = new MongoRepository<LocalItem>(connectionString);
            foreach (var culture in cultures)
            {
                itemTosave.Id = Guid.NewGuid().ToString();
                itemTosave.Culture = culture;
                itemTosave.Value = string.Format("{0} - {1} - {2}", itemTosave.ControllerName, itemTosave.ActionName, itemTosave.Name);

                repoLocal.Add(itemTosave);
            }
        }

        private static void HandleControllers(string value)
        {
            if (GetControllers(value, true).Count == 0)
            {
                var tempItem = new ControllerItem { Id = Guid.NewGuid().ToString(), Name = value };
                var repo = new MongoRepository<ControllerItem>(connectionString);
                repo.Add(tempItem);
            }

        }

        private static void HandleActions(string value, string controllerName)
        {
            if (GetActions(value, controllerName, true).Count == 0)
            {
                var tempController = GetControllers(controllerName, true).SingleOrDefault();

                var tempItem = new ActionItem { Id = Guid.NewGuid().ToString(), Name = value, ControllerId = (tempController != null ? tempController.Id : "unknown") };
                var repo = new MongoRepository<ActionItem>(connectionString);
                repo.Add(tempItem);
            }
        }

        private static void HandleCultures(string value)
        {
            if (GetCultures(value, true).Count == 0)
            {
                var tempItem = new Culture { Id = Guid.NewGuid().ToString(), Name = value };
                var repo = new MongoRepository<Culture>(connectionString);
                repo.Add(tempItem);
            }
        }


        #endregion

        #region Translate
        public static TranslateItem GetValuesToTranslate(string localId)
        {
            var repo = new MongoRepository<LocalItem>(connectionString);
            var item = repo.GetById(localId);

            var items = repo.All().Where(p => p.Name == item.Name &&
                p.ActionName == item.ActionName && p.ControllerName == item.ControllerName && p.Culture != item.Culture).
                Select(p => new SimpleLocal(p)).ToList();

            var ret = new TranslateItem
            {
                Original = item,
                Translations = items
            };

            return ret;
        }

        public static void SaveTranslation(string id, string newValue)
        {
            var repo = new MongoRepository<LocalItem>(connectionString);

            var item = repo.GetById(id);
            item.Value = newValue;

            repo.Update(item);
        }
        #endregion

        #region Lookup values

        public static List<Culture> GetCultures(string filter, bool exact = false)
        {
            var repo = new MongoRepository<Culture>(connectionString);
            var ret = repo.All();

            if (!string.IsNullOrEmpty(filter))
            {
                if (exact)
                {
                    ret = ret.Where(p => p.Name.Equals(filter));
                }
                else
                {
                    ret = ret.Where(p => p.Name.Contains(filter));
                }
            }

            return ret.ToList();
        }

        public static List<ControllerItem> GetControllers(string filter, bool exact = false)
        {
            var repo = new MongoRepository<ControllerItem>(connectionString);
            var ret = repo.All();

            if (!string.IsNullOrEmpty(filter))
            {
                if (exact)
                {
                    ret = ret.Where(p => p.Name.Equals(filter));
                }
                else
                {
                    ret = ret.Where(p => p.Name.Contains(filter));
                }
            }

            return ret.ToList();
        }

        public static List<ActionItem> GetActions(string filter, string controllerName, bool exact = false)
        {
            var repoController = new MongoRepository<ControllerItem>(connectionString);
            var tempController = repoController.All().SingleOrDefault(p => p.Name.Equals(controllerName));
            var repo = new MongoRepository<ActionItem>(connectionString);
            var ret = repo.All();

            if (!string.IsNullOrEmpty(filter))
            {
                if (exact)
                {
                    ret = ret.Where(p => p.Name.Equals(filter));
                }
                else
                {
                    ret = ret.Where(p => p.Name.Contains(filter));
                }
            }

            if (tempController != null)
            {
                ret = ret.Where(p => p.ControllerId.Equals(tempController.Id));
            }

            return ret.ToList();
        }

        public static List<string> GetNames(string filter)
        {
            var repo = new MongoRepository<LocalItem>(connectionString);
            var ret = repo.All().Select(p => p.Name).Distinct();

            if (!string.IsNullOrEmpty(filter))
            {
                ret = ret.Where(p => p.Contains(filter));
            }

            return ret.ToList();
        }
        #endregion
    }
}
